using System;
using System.Data;
using OracleInternal.Common;
using OracleInternal.MTS;

namespace Oracle.ManagedDataAccess.Client
{
	public class OracleLogicalTransaction : IDisposable
	{
		internal OracleConnection m_connection;

		internal bool? bDistributed;

		internal OracleConnection m_connforTxnStatus;

		internal byte[] m_ltxId;

		private string m_conString;

		private bool? m_bCommitted;

		private bool? m_bUserCallCompleted;

		private bool m_disposed;

		public bool? Committed => m_bCommitted;

		public bool? UserCallCompleted => m_bUserCallCompleted;

		public string ConnectionString => m_conString;

		public byte[] LogicalTransactionId
		{
			get
			{
				if (bDistributed == false && (!m_bCommitted.HasValue || !m_bUserCallCompleted.HasValue))
				{
					return m_ltxId;
				}
				return null;
			}
		}

		internal OracleLogicalTransaction(OracleConnection connection, byte[] ltxId)
		{
			m_connection = connection;
			if (ltxId != null)
			{
				m_ltxId = (byte[])ltxId.Clone();
			}
			if (connection == null || connection.m_oracleConnectionImpl == null)
			{
				return;
			}
			if (connection.m_oracleConnectionImpl.m_mtsTxnCtx != null && connection.m_oracleConnectionImpl.m_mtsTxnCtx.m_txnType == MTSTxnType.Distributed)
			{
				bDistributed = true;
			}
			else
			{
				bDistributed = false;
			}
			if (connection.m_oracleConnectionImpl.m_cs != null)
			{
				if (connection.m_oracleConnectionImpl.m_cs.m_proxyUserId == null || connection.m_oracleConnectionImpl.m_cs.m_proxyUserId == string.Empty)
				{
					m_conString = $"user id={connection.m_oracleConnectionImpl.m_cs.m_userId};data source={connection.m_oracleConnectionImpl.m_cs.m_dataSource};pooling=false";
				}
				else
				{
					m_conString = $"user id={connection.m_oracleConnectionImpl.m_cs.m_userId};data source={connection.m_oracleConnectionImpl.m_cs.m_dataSource};proxy user id={connection.m_oracleConnectionImpl.m_cs.m_proxyUserId};pooling=false";
				}
			}
		}

		~OracleLogicalTransaction()
		{
			Dispose();
		}

		public void Dispose()
		{
			if (m_disposed)
			{
				return;
			}
			try
			{
				GC.SuppressFinalize(this);
				try
				{
					if (m_connforTxnStatus != null)
					{
						m_connforTxnStatus.Dispose();
						m_connforTxnStatus = null;
					}
				}
				catch
				{
				}
			}
			finally
			{
				m_connection = null;
				m_disposed = true;
			}
		}

		public static void GetOutcome(string constring, byte[] ltxid, out bool? bCommitted, out bool? bUserCallCompleted)
		{
			OracleConnection oracleConnection = null;
			bCommitted = null;
			bUserCallCompleted = null;
			if (ProviderConfig.m_bTraceLevelPublic)
			{
				Trace.Write(OracleTraceLevel.Public, OracleTraceTag.Entry, OracleTraceClassName.OracleLogicalTransaction, OracleTraceFuncName.GetOutcome);
			}
			try
			{
				if (ltxid == null)
				{
					throw new ArgumentNullException("LogicalTransactionId");
				}
				oracleConnection = new OracleConnection(constring);
				oracleConnection.Open();
				if (!oracleConnection.m_isDb12cR1OrHigher)
				{
					throw new InvalidOperationException(OracleStringResourceManager.GetErrorMesg(ResourceStringConstants.CON_FEATURE_NOT_AVAILABLE, oracleConnection.ServerVersion));
				}
				OracleLogicalTransaction oracleLogicalTransaction = new OracleLogicalTransaction(oracleConnection, ltxid);
				oracleLogicalTransaction.GetOutcome(oracleConnection);
				bCommitted = oracleLogicalTransaction.Committed;
				bUserCallCompleted = oracleLogicalTransaction.UserCallCompleted;
			}
			finally
			{
				try
				{
					oracleConnection.Dispose();
				}
				catch
				{
				}
				if (ProviderConfig.m_bTraceLevelPublic)
				{
					Trace.Write(OracleTraceLevel.Public, OracleTraceTag.Exit, OracleTraceClassName.OracleLogicalTransaction, OracleTraceFuncName.GetOutcome);
				}
			}
		}

		internal void GetOutcome(OracleConnection con)
		{
			OracleCommand oracleCommand = null;
			OracleParameter oracleParameter = null;
			OracleParameter oracleParameter2 = null;
			OracleParameter oracleParameter3 = null;
			try
			{
				con.bConnectionforTxnStatus = true;
				oracleCommand = new OracleCommand(OracleConnection.s_getLTXIDstatus, con);
				oracleParameter = oracleCommand.Parameters.Add(null, OracleDbType.Raw, ParameterDirection.Input);
				oracleParameter.Value = m_ltxId;
				oracleParameter2 = oracleCommand.Parameters.Add("committed", (object)0);
				oracleParameter2.DbType = DbType.Int16;
				oracleParameter2.Direction = ParameterDirection.InputOutput;
				oracleParameter3 = oracleCommand.Parameters.Add("userCallCompleted", (object)0);
				oracleParameter3.DbType = DbType.Int16;
				oracleParameter3.Direction = ParameterDirection.InputOutput;
				oracleCommand.CommandTimeout = 15;
				oracleCommand.ExecuteNonQuery();
				if ((short)oracleParameter2.Value == 1)
				{
					m_bCommitted = true;
				}
				else
				{
					m_bCommitted = false;
				}
				if ((short)oracleParameter3.Value == 1)
				{
					m_bUserCallCompleted = true;
				}
				else
				{
					m_bUserCallCompleted = false;
				}
			}
			finally
			{
				oracleParameter.Dispose();
				oracleParameter2.Dispose();
				oracleParameter3.Dispose();
				oracleCommand.Dispose();
			}
		}

		internal void GetOutcome()
		{
			if (ProviderConfig.m_bTraceLevelPrivate)
			{
				Trace.Write(OracleTraceLevel.Private, OracleTraceTag.Entry, OracleTraceClassName.OracleLogicalTransaction, OracleTraceFuncName.GetOutcome);
			}
			try
			{
				if (!m_bCommitted.HasValue)
				{
					if (m_connection != null)
					{
						m_connforTxnStatus = (OracleConnection)m_connection.Clone();
					}
					m_connforTxnStatus.Open();
					if (!m_connforTxnStatus.m_isDb12cR1OrHigher)
					{
						throw new InvalidOperationException(OracleStringResourceManager.GetErrorMesg(ResourceStringConstants.CON_FEATURE_NOT_AVAILABLE, m_connforTxnStatus.ServerVersion));
					}
					GetOutcome(m_connforTxnStatus);
					m_connforTxnStatus.Dispose();
				}
			}
			catch (Exception ex)
			{
				if (ProviderConfig.m_bTraceLevelPrivate)
				{
					Trace.Write(OracleTraceLevel.Private, OracleTraceTag.Error, OracleTraceClassName.OracleLogicalTransaction, OracleTraceFuncName.GetOutcome, Trace.GetCPInfo(null, null, null, null) + ex.ToString());
				}
			}
			finally
			{
				try
				{
					if (m_connforTxnStatus != null && m_connforTxnStatus.State == ConnectionState.Open)
					{
						m_connforTxnStatus.Close();
					}
				}
				catch
				{
				}
				if (ProviderConfig.m_bTraceLevelPrivate)
				{
					Trace.Write(OracleTraceLevel.Private, OracleTraceTag.Exit, OracleTraceClassName.OracleLogicalTransaction, OracleTraceFuncName.GetOutcome);
				}
			}
		}
	}
}
